home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / docs / gccfaq10 / dma.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-15  |  7.6 KB  |  441 lines

  1. #include "dma.h"
  2.  
  3. #define TIMER
  4.  
  5. struct WAVHeaderStruct WAVHeader;
  6. struct SoundStruct Sound;
  7. struct DMAStruct DMA;
  8. struct WAVStruct WAV;
  9.  
  10. static unsigned short dos_segment;
  11. static unsigned int source, dest, length, blank_length;
  12.  
  13. int main(int argc, char *argv[])
  14. {
  15.  char c;
  16.  #if !defined TIMER
  17.   int count;
  18.  #endif
  19.  
  20.  printf("go32 a.out [filename].wav\n");
  21.  
  22.  c = 0;
  23.  
  24.  DMA.stat = 0;
  25.  dos_segment = _go32_conventional_mem_selector();
  26.  
  27.  /* Sound blaster settings. Sound.dma is always 1 */
  28.  
  29.  Sound.port = 0x220;
  30.  Sound.irq = 5;
  31.  Sound.dma = 1;
  32.  
  33.  /* Chain prior to malloc */
  34.  
  35.  DMAChain();
  36.  
  37.  if (!WAVLoad(argv[1])) {
  38.   printf("Could not load WAV file.\n");
  39.   DMAShutDown();
  40.   exit(-1);
  41.  }
  42.  
  43.  if (!DMAInit()) {
  44.   printf("Cound not init DMA/SB.\n");
  45.   DMAShutDown();
  46.   exit(-1);
  47.  }
  48.  
  49.  printf("Press [RETURN] to play, any other key to exit.\n");
  50.  
  51.  /* Loop */
  52.  
  53.  while (!c) {
  54.   #if defined TIMER
  55.    while(!kbhit());
  56.   #else
  57.    while(!kbhit()) {
  58.     if (rawclock()!=count) {
  59.      count = rawclock();
  60.      DMAPoll();
  61.    }}
  62.   #endif
  63.   
  64.   c = getkey();
  65.   if (c == 13) {
  66.    c = 0;
  67.    DMAPlayWAV();
  68.  }}
  69.  
  70.  /* Cleanup */
  71.  
  72.  DMAShutDown();
  73.  
  74.  free(WAV.offset);
  75.  
  76.  return(0);
  77. }
  78.  
  79. int WAVLoad(char *filename)
  80. {
  81.  FILE *fp;
  82.  
  83.  if (!(fp=fopen(filename, "rb"))) return(FALSE);
  84.  
  85.  if (!(fread(&WAVHeader, sizeof (WAVHeader), 1, fp))) return(FALSE);
  86.  
  87.  if (strncmp(WAVHeader.did, "data", 4) ||
  88.      WAVHeader.channels != 1) return(FALSE);
  89.  
  90.  WAV.length = WAVHeader.dlen;
  91.  DMA.wav_frequency = WAVHeader.frequency;
  92.  
  93.  if ((WAV.offset = malloc (WAV.length)) == NULL) return(FALSE);
  94.  
  95.  if (!(fread(WAV.offset, WAV.length, 1, fp))) return(FALSE);
  96.  
  97.  fclose(fp);
  98.  
  99.  return(TRUE);
  100. }
  101.  
  102. void DMAPlayWAV(void)
  103. {
  104.  asm ("cli");
  105.  
  106.  DMA.wav_offset = (int) WAV.offset;
  107.  DMA.wav_length = WAV.length;
  108.  
  109.  asm ("sti");
  110.  
  111.  if (!(DMA.stat & DMA_RUNNING)) DMAStart();
  112. }
  113.  
  114.  
  115. void DMAChain()
  116. {
  117.  _go32_dpmi_seginfo handler;
  118.  
  119.  /* Chain sb irq */
  120.  
  121.  handler.pm_offset = (int) DMAInterrupt;
  122.  handler.pm_selector = _go32_my_cs();
  123.  
  124.  _go32_dpmi_get_protected_mode_interrupt_vector(8 + Sound.irq, &DMA.old_irq_handler);
  125.  _go32_dpmi_chain_protected_mode_interrupt_vector(8 + Sound.irq, &handler);
  126.  
  127.  /* Chain timer */
  128.  
  129.  #if defined TIMER
  130.   handler.pm_offset = (int) DMAPoll;
  131.  
  132.   _go32_dpmi_get_protected_mode_interrupt_vector(8, &DMA.old_timer_handler);
  133.   _go32_dpmi_chain_protected_mode_interrupt_vector(8, &handler);
  134.  #endif
  135.  
  136.  DMA.stat |= DMA_CHAINED;
  137. }
  138.  
  139. int DMAInit(void)
  140. {
  141.  int i;
  142.  unsigned char major, minor;
  143.  unsigned int addr, page;
  144.  _go32_dpmi_seginfo handler;
  145.  
  146.  /* Init */
  147.  
  148.  DMA.wav_length = 0;
  149.  
  150.  /* Allocate some DOS memory for the DMA buffers */
  151.  
  152.  DMA.dos_memory.size = (DMA_SIZE * 2) / 16;
  153.  if (_go32_dpmi_allocate_dos_memory(&DMA.dos_memory)) return(FALSE);
  154.  DMA.stat |= DMA_MEMORY_ALLOCATED;
  155.  
  156.  /* What is the 20 bit address? */
  157.  
  158.  addr = DMA.dos_memory.rm_segment << 4;
  159.  
  160.  /* See if we cross any 64K boundarys */
  161.   
  162.  page = addr & 0xffff;
  163.  if ((page + DMA_SIZE) > 0xffff) addr = (addr - page) + 0x10000;
  164.  
  165.  DMA.buffer_offset = addr;
  166.  
  167.  /* Reset SB DSP */
  168.  
  169.  inportb(Sound.port+0xa);
  170.  outportb(Sound.port+0x6, 1);
  171.  inportb(Sound.port+0x6);
  172.  inportb(Sound.port+0x6);
  173.  inportb(Sound.port+0x6);
  174.  inportb(Sound.port+0x6);
  175.  outportb(Sound.port+0x6, 0);                                      
  176.  
  177.  i = 0;
  178.  for (i = 0; i < 100; i++) {
  179.   if (inportb(Sound.port+0xe) & 0x08) {
  180.    if (inportb(Sound.port+0xa) == 0xaa) break;
  181.  }}
  182.  
  183.  if (i == 100) return(FALSE);
  184.  
  185.  DMA.stat |= SB_ACTIVE;
  186.  
  187.  /* Get DSP version, not used. */
  188.  
  189.  WriteDSP(0xe1);
  190.  major = ReadDSP();
  191.  minor = ReadDSP();
  192.  
  193.  /* Enable interrupts on PIC */
  194.  
  195.  major = inportb(0x21);
  196.  minor = ~(1 << Sound.irq);
  197.  outportb(0x21, major & minor);
  198.  
  199.  /* Set Time Constant */
  200.  
  201.  inportb(Sound.port+0xe);
  202.  WriteDSP(0x40);
  203.  WriteDSP(256-(1000000/DMA.wav_frequency));
  204.  
  205.  /* SpkOn */
  206.  
  207.  WriteDSP(0xd1);
  208.   
  209.  /* Silence in buffer */
  210.  
  211.  length = DMA_SIZE / 4;
  212.  dest = DMA.buffer_offset;
  213.  
  214.  asm ("
  215.   pushw %es
  216.   
  217.   movw _dos_segment, %es
  218.   movl _length, %ecx
  219.   movl _dest, %edi
  220.   movl $0x80808080, %eax
  221.    
  222.   rep ; stosl
  223.   
  224.   popw %es
  225.  ");
  226.  
  227.  return(TRUE);
  228. }
  229.  
  230. void DMAShutDown(void)
  231. {
  232.  /* SpkOff */
  233.  
  234.  if (DMA.stat & SB_ACTIVE) WriteDSP(0xd3);
  235.  
  236.  /* Stop any DMA transfer */
  237.  
  238.  DMAStop();
  239.  
  240.  /* Free memory */
  241.  
  242.  if (DMA.stat & DMA_MEMORY_ALLOCATED) {
  243.   _go32_dpmi_free_dos_memory(&DMA.dos_memory);
  244.   DMA.stat -= DMA_MEMORY_ALLOCATED;
  245.  }
  246.   
  247.  /* Unchain interrupts */
  248.  
  249.  if (DMA.stat & DMA_CHAINED) {
  250.   #if defined TIMER
  251.    _go32_dpmi_set_protected_mode_interrupt_vector(8, &DMA.old_timer_handler);
  252.   #endif
  253.   _go32_dpmi_set_protected_mode_interrupt_vector(8 + Sound.irq, &DMA.old_irq_handler);
  254.   DMA.stat -= DMA_CHAINED;
  255.  }
  256. }
  257.  
  258. void WriteDSP(char data)
  259. {
  260. /* int i;
  261.  
  262.  for (i = 0;(inportb(Sound.port+0xc) & 0x80) && i < DSP_TIMEOUT; i++);
  263. */
  264.  while(inportb(Sound.port+0xc) & 0x80);
  265.  outportb(Sound.port+0xc, data);
  266. }
  267.  
  268. unsigned char ReadDSP(void)
  269. {
  270. /* int i;
  271.  
  272.  for (i = 0;(inportb(Sound.port+0xe) & 0x80) && i < DSP_TIMEOUT; i++);
  273. */
  274.  while(!(inportb(Sound.port+0xe) & 0x80));
  275.  return(inportb(Sound.port+0xa));
  276. }
  277.  
  278. void DMAInterrupt(void)
  279. {
  280.  asm ("cli;pusha");
  281.  
  282.  /* Acknowledge SB */
  283.  
  284.  inportb(Sound.port+0xe);
  285.  
  286.  /* Tell SB to accept next block */
  287.  
  288.  WriteDSP(0x14);
  289.  WriteDSP(0xff);
  290.  WriteDSP(0xff);
  291.  
  292.  /* Acknowledge interrupt */
  293.  
  294.  outportb(0x20, 0x20);
  295.  asm ("popa;sti");
  296. }
  297.  
  298. static unsigned short word;
  299.  
  300. short DMACount()
  301. {
  302.  asm ("
  303.   inb  $03, %al
  304.   movb %al, %cl
  305.   inb  $03, %al
  306.   movb %al, %ch
  307.   movw %cx, _word
  308.  ");
  309.  return (DMA_SIZE - word);
  310. }
  311.  
  312. void DMAStop()
  313. {
  314.  if (DMA.stat & DMA_RUNNING) {
  315.   WriteDSP(0xd0);
  316.   DMA.stat -= DMA_RUNNING;
  317.  }
  318. }
  319.  
  320. void DMAStart(void)
  321. {
  322.  unsigned int size;
  323.  
  324.  size = DMA_SIZE - 1;
  325.  
  326.  outportb(0x0a, 0x05);
  327.  outportb(0x0c, 0x00);
  328.  outportb(0x0b, 0x59);
  329.  
  330.  outportb(0x02, DMA.buffer_offset);
  331.  outportb(0x02, DMA.buffer_offset >> 8);
  332.  outportb(0x83, DMA.buffer_offset >> 16);
  333.  
  334.  outportb(0x03, size);
  335.  outportb(0x03, size >> 8);
  336.  outportb(0x0a, 0x01);
  337.  
  338.  WriteDSP(0x14);
  339.  WriteDSP(0xff);
  340.  WriteDSP(0xff);
  341.  
  342.  DMA.stat |= DMA_RUNNING;
  343.  DMA.flag = TRUE;
  344.  DMA.count = 0;
  345. }
  346.  
  347. void DMAPoll(void)
  348. {
  349.  short count;
  350.  
  351.  if (DMA.stat & DMA_RUNNING) {
  352.  
  353.   count = DMACount();
  354.   dest = 0;
  355.  
  356.   /* DMA should be running */
  357.  
  358.   if (DMA.count == count) {
  359.  
  360.    /* DMA has halted, restart it */
  361.  
  362.    if (DMA.flag) {
  363.     DMAStart(); 
  364.     count = 0;        /* Start filling 2nd 1/2 */
  365.     DMA.flag = TRUE;
  366.    } else {
  367.     DMAStart();   
  368.     count = DMA_SIZE; /* Start filling 1st 1/2 */
  369.     DMA.flag = FALSE;
  370.    }
  371.   }
  372.  
  373.   DMA.count = count;
  374.  
  375.   /* What half of the buffer are we in? */
  376.  
  377.   if (DMA.flag) {
  378.    if (count < DMA_SIZE/2) {
  379.     dest = DMA.buffer_offset + DMA_SIZE/2;
  380.     DMA.flag = FALSE;
  381.    }
  382.   } else {
  383.    if (count >= DMA_SIZE/2) {
  384.     dest = DMA.buffer_offset;
  385.     DMA.flag = TRUE;
  386.    }
  387.   }
  388.  
  389.   /* Can we go ahead and fill 1/2 buffer? */
  390.  
  391.   if (dest) {
  392.    
  393.    /* Is there anything to fill it with? */
  394.    
  395.    length = DMA.wav_length;
  396.  
  397.    if (length) {
  398.  
  399.     if (length > DMA_SIZE/2) length = DMA_SIZE/2;
  400.  
  401.     source = DMA.wav_offset;
  402.  
  403.     DMA.wav_length -= length;
  404.     DMA.wav_offset += length;
  405.    }
  406.  
  407.    blank_length = (DMA_SIZE/2) - length;
  408.  
  409.    asm ("
  410.     pushw %es
  411.  
  412.     movw _dos_segment, %es
  413.     movl _dest, %edi
  414.     movl _length, %ecx
  415.  
  416.     testl %ecx, %ecx
  417.     jz no_sound
  418.  
  419.     movl _source, %esi
  420.  
  421.     rep ; movsb
  422.  
  423.    no_sound:
  424.  
  425.     movl _blank_length, %ecx
  426.  
  427.     testl %ecx, %ecx
  428.     jz no_more
  429.  
  430.     movb $0x80, %al
  431.  
  432.     rep ; stosb
  433.     
  434.    no_more:
  435.  
  436.     popw %es
  437.    ");
  438.   } 
  439.  }
  440. }
  441.